package fun.ticsmyc.rpc.server.provider.impl;

import fun.ticsmyc.rpc.common.entity.TRPCServiceProperties;
import fun.ticsmyc.rpc.common.enumeration.RpcError;
import fun.ticsmyc.rpc.common.exception.RpcException;
import fun.ticsmyc.rpc.server.provider.ServiceProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 使用一个Map存储服务信息， key value 是 【接口名 ： 实现类】
 *
 * 默认一个接口只对应一个实现类
 *
 * @author Ticsmyc
 * @date 2020-10-23 16:07
 */
public class DefaultServiceProvider implements ServiceProvider {

    private static final Logger logger = LoggerFactory.getLogger(DefaultServiceProvider.class);
    private static Map<String,Object> serviceMap = null;
    private volatile static DefaultServiceProvider INSTANCE=null;


    //懒加载
    private DefaultServiceProvider(){}
    public static DefaultServiceProvider getInstance(){
        if(INSTANCE == null){
            synchronized (DefaultServiceProvider.class){
                if(INSTANCE == null){
                    INSTANCE = new DefaultServiceProvider();
                    serviceMap = new ConcurrentHashMap<>();
                }
            }
        }
        return INSTANCE;
    }

    /**
     * 这里是由于 register方法一般都是由BeanPostProcessor在IOC启动时调用，
     * 一般应该是单线程的， 加一个synchronized以防万一（反正偏向锁，基本不影响性能）
     * @param service
     * @param trpcServiceProperties
     */
    @Override
    public synchronized void register(Object service, TRPCServiceProperties trpcServiceProperties) {
        //获取由Java语言规范定义的基础类的规范名称。
        // 接口名 -> 实现类
        String serviceName = trpcServiceProperties.getSignature();
        if(!serviceMap.containsKey(serviceName)){
            serviceMap.put(serviceName,service);
        }
        logger.debug("向接口 {} ,注册服务 {}",serviceName,service.getClass().getCanonicalName());
    }

    @Override
    public Object getService(String serviceName) {
        Object service = serviceMap.get(serviceName);
        if(service == null){
            throw new RpcException(RpcError.SERVICE_NOT_FOUNT);
        }
        return service;
    }
}
